#include "usart.h"

/*
  一个总的缓冲区，用于接收后的字符串
  再来一个数组用来存放每次进入的数据长度起始地址和末尾地址
  开DMA 
  开串口空闲中断 
*/

uint8_t U1_RxBuff[U1_RxBuff_Size];
uint8_t U1_TxBuff[U1_TxBuff_Size];     //串口0发送缓冲区
U_CB U1_CB;

void USART1_Init(uint32_t bound)
{
    /*enable clock and gpio*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    /*PA9 TX PA10 RX*/
    /*configure GPIO and USART*/
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    USART_DeInit(USART1);
    USART_InitTypeDef USART_InitStructure;
    USART_InitStructure.USART_BaudRate = bound;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_Init(USART1, &USART_InitStructure);
    
    //enable interrupt
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=5 ; //抢占优先级 数值越小 优先级越高 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级 -- 响应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
    NVIC_Init(&NVIC_InitStructure); //配置优先级初始化

    //开启接收寄存器非空中断
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); //开启空闲中断
    USART_Cmd(USART1, ENABLE);
    //开启DMA接收
    U1RX_DMA_Init();
    //初始化指针
    U1_ptr_init();
}

DMA_InitTypeDef DMA_InitStructure;
void U1RX_DMA_Init()
{
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
    DMA_DeInit(DMA1_Channel5); //DMA 通道复位 通道5
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR); //DMA 通道的外设基地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)U1_RxBuff; //DMA 通道的内存基地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //DMA 方向，从外设读取数据到内存
    DMA_InitStructure.DMA_BufferSize = U1_RxMaxSize; //DMA 通道的缓冲区大小
    DMA_InitStructure.DMA_PeripheralDataSize= DMA_PeripheralDataSize_Byte; //DMA 通道的外设数据大小
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //DMA 通道的内存数据大小
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //DMA 通道的外设地址是否自增
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //DMA 通道的内存地址是否自增
    DMA_InitStructure.DMA_Mode =DMA_Mode_Circular ; //循环模式
    DMA_InitStructure.DMA_Priority=DMA_Priority_High;//DMA 通道的优先级

    DMA_Init(DMA1_Channel5, &DMA_InitStructure); //DMA 通道初始化
    USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE); //DMA 通道使能
    DMA_Cmd(DMA1_Channel5, ENABLE); //DMA 通道使能
}   

void U1_ptr_init()
{
    U1_CB.U_Data_IN=&U1_CB.U1_Rx_Ptr_Buff[0];//接收指针
    U1_CB.U_Data_OUT=&U1_CB.U1_Rx_Ptr_Buff[0];//发送指针

    U1_CB.U_Data_IN->start=U1_RxBuff;
    U1_CB.U_Data_IN->end=U1_RxBuff;
    U1_CB.U_Data_OUT->start=U1_RxBuff;
    U1_CB.U_Data_OUT->end=U1_RxBuff;
    
    U1_CB.U_Data_end=&U1_CB.U1_Rx_Ptr_Buff[U1_Rx_Ptr_Buff_Num-1];//接收数组末尾指针
    U1_CB.U_Data_counter=0;//接收数据计数
    memcpy(U1_RxBuff,"0",2048);
}

void Send_Byte(uint8_t byte)
{
    USART_SendData(USART1, byte);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);//等待发射寄存器为空后返回
    return;
}

void u1_printf(char *format, ...) 
{
    va_list listdata;                   //char * 类型
    va_start(listdata, format);         //初始化va_list，使其指向第一个可变参数（位于固定参数format之后
    /*将可变参数按format格式化为字符串，并写入缓冲区U1_TxBuff。该函数会自动处理类型转换（如%d、%s等）
    并确保输出不超过缓冲区大小（通过sizeof(U1_TxBuff)限制）*/
    vsnprintf((char*)U1_TxBuff, sizeof(U1_TxBuff), format, listdata);
    va_end(listdata);                   //清理valist指针 防止野指针

    /*将格式化后的字符串逐个字节发送到串口*/
    for(int i = 0; i < strlen((char*)U1_TxBuff); i++)
    {
        Send_Byte(U1_TxBuff[i]);
    }
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); //等待发送完成
}